package other.edan.erp.k3;

import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.ScheduleJob;
import com.rkhd.platform.sdk.api.annotations.RequestMethod;
import com.rkhd.platform.sdk.api.annotations.RestApi;
import com.rkhd.platform.sdk.api.annotations.RestMapping;
import com.rkhd.platform.sdk.data.model.ShippingPersonnelSheet__c;
import com.rkhd.platform.sdk.data.model.SyncConfig__c;
import com.rkhd.platform.sdk.exception.AsyncTaskException;
import com.rkhd.platform.sdk.exception.ScriptBusinessException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.param.ScheduleJobParam;
import com.rkhd.platform.sdk.service.FutureTaskService;
import com.rkhd.platform.sdk.service.XoqlService;
import com.rkhd.platform.sdk.task.FutureTask;
import org.apache.commons.lang.StringUtils;
import other.edan.erp.utils.HCDateUtils;
import other.edan.erp.utils.HCXObjectService;
import other.edan.erp.utils.ResultVo;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 检查出货数据是否异常，异常数据赋值进行提示
 * @Author: 黎炎松
 * @Date: 2024/12/24 13:40
 */
@RestApi(baseUrl = "/edan/shipment")
public class CheckShipmentData extends SyncSuper implements ScheduleJob, FutureTask {
    private static XoqlService xoqlService = XoqlService.instance();
    private static final Logger LOGGER = LoggerFactory.getLogger();
    private static String LOGGER_MSG = "检查出货数据 ==> ";
    // 动物部门id
    private static List<Long> animalDeptIds = Arrays.asList(3351255223884428L, 3351255389805139L, 3351255343045222L, 3351255640595039L);
    // 非空字段
    private static Map<String, String> nonEmptyField = new LinkedHashMap<String, String>(){{
        put("shiJiBuMen__c", "实际部门");
        put("number__c", "数量");
        put("customItem25__c", "办事处确认业务员");
        put("salesmanNum__c", "办事处确认业务员工号");
        put("splitRatio__c", "划分比例");
        put("yeJiJinE__c", "业绩划分金额");
    }};

    /**
     * 手动触发出库同步
     * @param
     * @return
     */
    @RestMapping(value = "/handerCheck", method = RequestMethod.POST)
    public ResultVo handerCheck() throws AsyncTaskException {
        LOGGER.debug("手动触发同步");
        String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
        LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        return ResultVo.success("开始同步");
    }

    // 执行定时任务
    @Override
    public void execute(ScheduleJobParam scheduleJobParam) {
        LOGGER.debug(LOGGER_MSG + " 执行定时任务开始");
        try {
            String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
            LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        } catch (Exception e) {
            LOGGER.error(LOGGER_MSG + " ----- 发生异常：" + e.getMessage());
        }
    }

    // 执行异步函数
    @Override
    public void execute(String s) throws ScriptBusinessException {
        dealAddShipmentByOut();
    }

    public static void main(String[] args) {
        HCXObjectService.isLocal = true;
        CheckShipmentData checkShipmentData = new CheckShipmentData();
        checkShipmentData.dealAddShipmentByOut();
    }

    /**
     * 根据销售出库明细处理新增的出货数据
     * @return
     */
    public ResultVo dealAddShipmentByOut() {
        try {
            LOGGER.info(LOGGER_MSG + "开始检查");

            // 从数据配置表中获取数据
            SyncConfig__c syncConfig = getSyncConfig("CHECK_SHIPMENT");
            Long startDate = HCDateUtils.stringToLong(syncConfig.getAttribute("startDate"), HCDateUtils.FORMATTIME);
            Long endDate = HCDateUtils.stringToLong(syncConfig.getAttribute("endDate"), HCDateUtils.FORMATTIME);

            // 根据变化的出货数据找到对应的销售出库明细
            String  sql = String.format("select salesOutReceiptDetails__c from shippingPersonnelSheet__c " +
                    " where entityType = 3533390342314578 and updatedAt between %s and %s", startDate, endDate);
            String outDetailIds = HCXObjectService.queryAllUseXoql(sql).stream().map(v -> v.getString("salesOutReceiptDetails__c")).distinct().collect(Collectors.joining(","));
            if (StringUtils.isBlank(outDetailIds)) {
                LOGGER.info(LOGGER_MSG + "没有需要处理的销售出库明细数据");
                upSyncConfig(syncConfig);
                return ResultVo.success("没有需要处理的销售出库明细数据", null);
            }

            // 查询出货数据,按销售出库明细进行分组
            sql = String.format("select id,name,errorTips__c,salesOutReceiptDetails__c,salesOutReceiptDetails__c.chanPinXian__c productLine," +
                    " salesOutReceiptDetails__c.chanPinFenLei__c productClassification,salesOutReceiptDetails__c.quantity__c quantity,salesOutReceiptDetails__c.haoCai__c materialNum," +
                    " customItem25__c.dimDepart dimDepart,customItem25__c,salesmanNum__c,shiJiBuMen__c,splitRatio__c,yeJiJinE__c,number__c,materialNum__c " +
                    " from shippingPersonnelSheet__c where salesOutReceiptDetails__c in (%s)", outDetailIds);
            Map<Long, List<JSONObject>> shipmentMap = HCXObjectService.queryAllUseXoql(sql).stream().collect(Collectors.groupingBy(e -> e.getLong("salesOutReceiptDetails__c")));
            System.out.println("shipmentMap = " + shipmentMap.size());

            // 进行数据处理
            List<ShippingPersonnelSheet__c> crmUpList = new ArrayList<>();
            for (Long outDetailId : shipmentMap.keySet()) {
                List<JSONObject> shipmentList = shipmentMap.get(outDetailId);

                // 明细数据单行判断
                List<JSONObject> filterList = new ArrayList<>();
                double totalQuantity = 0.0;
                double totalMaterialNum = 0.0;
                int radio_100 = 0;
                int radio_20 = 0;
                int radio_60 = 0;
                for (JSONObject shipment : shipmentList) {
                    ShippingPersonnelSheet__c upShipping = new ShippingPersonnelSheet__c();
                    upShipping.setErrorTips__c(null);

                    // 检查必填字段
                    List<String> tipsList = checkFieldIsEmpty(shipment);

                    // 判断划分比例的取值 默认是 100、20
                    Map<Integer, String> ratioMap = new HashMap<Integer, String>(){{
                        put(1, "100%");
                        put(2, "20%");
                    }};

                    // 判断是否运行比例可以包含 60  1.产品线是超声&不是否动物产品   2.产品分类是盆底
                    Integer productLine = shipment.getInteger("productLine"); // 产品线
                    Long dimDepart = shipment.getLong("dimDepart"); // 业务员部门
                    Integer productClassification = shipment.getInteger("productClassification"); // 产品分类
                    if ((Objects.equals(productLine, 4) && animalDeptIds.contains(dimDepart)) || Objects.equals(productClassification, 8)) {
                        ratioMap.put(3, "60%");
                    }
                    Integer splitRatio = shipment.getInteger("splitRatio__c"); // 划分比例 1：100%,2: 40%,3:70%
                    if (splitRatio != null && !ratioMap.containsKey(splitRatio)) {
                        String radioStr = ratioMap.values().stream().collect(Collectors.joining(","));
                        tipsList.add("当前数据划分比例选项只能是：" + radioStr);
                    }

                    // 如果比例是 20%， 清空数量、耗材数量
                    int isClear = 0;
                    boolean isNeedUpdate = shipment.getDouble("number__c") != null || shipment.getDouble("materialNum__c") != null; // 没有变化无需进行修改
                    if (Objects.equals(splitRatio, 2) && isNeedUpdate) {
                        isClear = 1;
                    } else if (Objects.equals(splitRatio, 3)) {
                        // 判断比例是 60% 的数据，则只保留一行的数量、耗材数量
                        filterList.add(shipment);
                        if (filterList.size() > 1 && isNeedUpdate) {
                            isClear = 1;
                        }
                    }
                    // 是否需要清空
                    if (isClear == 1) {
                        upShipping.setNumber__c(null);
                        upShipping.setMaterialNum__c(null);
                        shipment.put("number__c", 0);
                        shipment.put("materialNum__c", 0);
                    }

                    // 汇总数量
                    totalQuantity += shipment.getDoubleValue("number__c");
                    totalMaterialNum += shipment.getDoubleValue("materialNum__c");
                    if (Objects.equals(splitRatio, 1)) radio_100++;
                    if (Objects.equals(splitRatio, 2)) radio_20++;
                    if (Objects.equals(splitRatio, 3)) radio_60++;

                    // 如果之前有错误信息的，本次需要清空
                    String errorTips = shipment.getString("errorTips__c");
                    if (tipsList.size() > 0 || isClear == 1 || StringUtils.isNotBlank(errorTips)) {
                        upShipping.setId(shipment.getLong("id"));
                        if (tipsList.size() > 0) {
                            upShipping.setErrorTips__c(StringUtils.join(tipsList, ";"));
                        }
                        crmUpList.add(upShipping);
                    }
                }

                // 判断出货数据的数量总和是否等于销售出货明细的总和
                LOGGER.info(LOGGER_MSG + "判断出货数据的数量总和是否等于销售出货明细的总和");
                JSONObject tempShipment = shipmentList.stream().filter(v -> Objects.equals(v.getInteger("splitRatio__c"), 1)).findFirst().orElse(null);
                if (tempShipment == null) tempShipment =shipmentList.get(0);
                Long shipmentId = tempShipment.getLong("id");
                Double quantity = tempShipment.getDoubleValue("quantity");
                Double materialNum = tempShipment.getDoubleValue("materialNum");
                if (!Objects.equals(quantity, totalQuantity) || !Objects.equals(materialNum, totalMaterialNum)) {
                    // 当前明细
                    String tips = "出货明细数量、耗材数量总和不等于销售出库明细数量";
                    ShippingPersonnelSheet__c upShipping = crmUpList.stream().filter(v -> Objects.equals(v.getId(), shipmentId)).findFirst().orElse(null);
                    if (upShipping == null) {
                        String name = tempShipment.getString("name");
                        LOGGER.info(LOGGER_MSG + " name " + name);

                        upShipping = new ShippingPersonnelSheet__c();
                        upShipping.setId(shipmentId);
                        upShipping.setErrorTips__c(tips);
                        crmUpList.add(upShipping);
                    } else {
                        String errorTips = upShipping.getErrorTips__c();
                        if (StringUtils.isNotBlank(errorTips)) {
                            errorTips += ";" + tips;
                            upShipping.setErrorTips__c(errorTips);
                        } else {
                            upShipping.setErrorTips__c(tips);
                        }
                    }
                }

                // 计算比例总和
                int radioTotal = (radio_100 * 100) + (radio_20 * 20) + (radio_60 * 60);
                LOGGER.info(LOGGER_MSG + "计算比例总和 = " + radioTotal);
                if ((radio_20 > 0 || radio_60 > 0) && radioTotal != 120) {
                    // 比例总和只能为 120
                    String tips = "出货明细划分比例总和需要等于120%";
                    ShippingPersonnelSheet__c upShipping = crmUpList.stream().filter(v -> Objects.equals(v.getId(), shipmentId)).findFirst().orElse(null);
                    if (upShipping == null) {
                        String name = tempShipment.getString("name");
                        LOGGER.info(LOGGER_MSG + " name " + name);

                        upShipping = new ShippingPersonnelSheet__c();
                        upShipping.setId(shipmentId);
                        upShipping.setErrorTips__c(tips);
                        crmUpList.add(upShipping);
                    } else {
                        String errorTips = upShipping.getErrorTips__c();
                        if (StringUtils.isNotBlank(errorTips)) {
                            errorTips += ";" + tips;
                            upShipping.setErrorTips__c(errorTips);
                        } else {
                            upShipping.setErrorTips__c(tips);
                        }
                    }
                }

                if (crmUpList.size() > 50) {
                    HCXObjectService.updateBatch(crmUpList);
                    crmUpList.clear();
                }
            }
            System.out.println("crmUpList = " + crmUpList);
            LOGGER.info(LOGGER_MSG + "crmUpList = " + crmUpList.size());
            HCXObjectService.updateBatch(crmUpList);

            // 同步修改配置表
            upSyncConfig(syncConfig);

            LOGGER.info(LOGGER_MSG + "检查成功");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(LOGGER_MSG + "检查异常:" + e.getMessage());
            return ResultVo.error("检查异常:" + e.getMessage());
        }
    }

    /**
     * 检查空字段
     * @param shipment
     * @return
     */
    public List<String> checkFieldIsEmpty(JSONObject shipment) {
        List<String> tipsList = new ArrayList<>();
        List<String> emptyList = new ArrayList<>();
        for (String key : nonEmptyField.keySet()) {
            if (shipment.get(key) == null) {
                emptyList.add(nonEmptyField.get(key));
            }
        }
        if (emptyList.size() > 0) {
            tipsList.add(String.format("必填字段不可为空(%s)", StringUtils.join(emptyList, ",")));
        }
        return tipsList;
    }


}
